/*
 * vector.h
 *
 *  Created on: 28.06.2011
 *      Author: marcell
 */

#ifndef __INKA_MATH_VECTOR_HH__
#define __INKA_MATH_VECTOR_HH__

#include <math.h>

namespace inka
{
namespace math
{

template<typename T>
struct Vector2
{
    T x;
    T y;
    inline Vector2 (T x = 0, T y = 0) : x(x), y(y) { }
};

typedef Vector2<float>  Vector2f;
typedef Vector2<int>    Vector2i;
typedef Vector2<short>  Vector2s;

template<typename T>
struct Vector3
{
    T x;
    T y;
    T z;

    inline Vector3 () : x(0), y(0), z(0) {}

    inline Vector3 (T x, T y, T z) : x(x), y(y), z(z) { }

    inline Vector3<T> operator+ (const Vector3<T>& v) const
    {
      return Vector3<T> (x + v.x, y + v.y, z + v.z);
    }

    inline Vector3<T> operator- (const Vector3<T>& v) const
    {
      return Vector3 (x - v.x, y - v.y, z - v.z);
    }

    inline Vector3<T>& operator+= (const Vector3<T>& v)
    {
      x += v.x;
      y += v.y;
      z += v.z;
      return *this;
    }

    inline Vector3<T>& operator-= (const Vector3<T>& v)
    {
      x -= v.x;
      y -= v.y;
      z -= v.z;
      return *this;
    }

    inline Vector3<T> operator* (const Vector3<T>& v) const
    {
      return Vector3<T> (x * v.x, y * v.y, z * v.z);
    }

    inline Vector3<T> operator* (T v) const
    {
      return Vector3<T> (x * v, y * v, z * v);
    }

    inline Vector3<T>& operator*= (T v)
    {
      x *= v;
      y *= v;
      z *= v;
      return *this;
    }

    inline Vector3<T> operator/ (T d) const
    {
      return Vector3<T> (x / d, y / d, z / d);
    }
    
    inline Vector3<T> operator/ (const Vector3<T>& d) const
    {
      return Vector3<T> (x / d.x, y / d.y, z / d.z);
    }

    inline Vector3<T>& operator/= (T d)
    {
      x /= d;
      y /= d;
      z /= d;
      return *this;
    }

    inline T Length () const
    {
      return sqrt (x*x + y*y + z*z);
    }

    inline T Dot () const
    {
      return x*x + y*y + z*z;
    }

    inline T Dot (const Vector3<T>& v) const
    {
      return x*v.x + y*v.y + z*v.z;
    }

    inline Vector3<T>& Normalize ()
    {
      T l = Length();
      x /= l;
      y /= l;
      z /= l;
      return *this;
    }

    inline Vector3<T> Normalized ()  const
    {
      T l = Length();
      return Vector3<T> (x / l, y / l, z / l);
    }

    inline Vector3<T> operator% (const Vector3<T>& v) const
    {
      return Vector3<T> (y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
    }

    inline T Angle (const Vector3<T>& other)
    {
      return acos(Normalized().Dot(other.Normalized()));
    }

    inline T Min() const
    {
      return x < y && x < z ? x : y < x && y < z ? y : z;
    }
};

typedef Vector3<float>  Vector3f;
typedef Vector3<int>    Vector3i;
typedef Vector3<short>  Vector3s;

template<typename T>
struct Vector4
{
    T x;
    T y;
    T z;
    T w;
    inline Vector4 (T x = 0.0f, T y = 0.0f, T z = 0.0f, T w = 1.0f) : x(x), y(y), z(z), w(w) { }
    inline Vector4 (const Vector3<T>& v, T w = 1.0f) : x(v.x), y(v.y), z(v.z), w(w) { }

    Vector3<T> AsVector3 ()
    {
      return Vector3<T>(x, y, z);
    }
};

typedef Vector4<float>  Vector4f;
typedef Vector4<int>    Vector4i;
typedef Vector4<short>  Vector4s;

}
}

#endif /* ! __INKA_MATH_VECTOR_H__ */
